package com.heima.article.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.contatns.ArticleConstants;
import com.heima.common.contatns.RedisConstants;
import com.heima.common.dtos.ResponseResult;
import com.heima.model.article.dtos.ArticleVisitStreamMsg;
import com.heima.model.article.dtos.HotArticleVo;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.wemeida.pojos.WmChannel;
import com.heima.utils.common.BeanHelper;
import com.heima.utils.common.JsonUtils;
import com.heima.wemedia.feign.WemediaFeign;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class HotArticleServiceImpl implements HotArticleService {
    @Autowired
    private WemediaFeign wemediaFeign;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ApArticleMapper apArticleMapper;
    @Override
    public void computeHotArticle() {
        //获取前5天的日期
        Date days = DateTime.now().minusDays(5).toDate();

        //查询近5天的文章
        List<ApArticle> apArticleList = apArticleMapper.findArticleListByLastDays(days);

        //计算分值
        List<HotArticleVo> hotArticleVoList = computeScoreForArticles(apArticleList);

        //指定不同频道的文章进行缓存
        ResponseResult<List<WmChannel>> responseResult = wemediaFeign.channels();
        if(responseResult.getCode().equals(200)){
            List<WmChannel> channelList = responseResult.getData();

            //不同频道的文章进行缓存，按照分值对每个频道的文章进行排序，截取前30条文章，存入Redis数据库
            if(CollectionUtils.isNotEmpty(channelList)){
                channelList.forEach(channel->{
                    //筛选出当前频道文章
                    List<HotArticleVo> curChannelHotArticle = hotArticleVoList.stream()
                                        .filter(hotArticleVo -> hotArticleVo.getChannelId().equals(channel.getId()) )
                                        .collect(Collectors.toList());

                    /*hotArticleVoList.forEach(hotArticleVo -> {
                        if(hotArticleVo.getChannelId().equals(channel.getId())){
                            curChannelHotArticle.add(hotArticleVo);
                        }
                    });*/
                    //当前频道缓存的key
                    String key = RedisConstants.HOT_ARTICLE_FIRST_PAGE+channel.getId();
                    sortedAndCacheHotArticle(key,curChannelHotArticle);
                });
            }

            //推荐频道文章缓存，按照分值对每个频道的文章进行排序，截取前30条文章，存入Redis数据库
            String key = RedisConstants.HOT_ARTICLE_FIRST_PAGE+RedisConstants.DEFAULT_TAG;
            sortedAndCacheHotArticle(key,hotArticleVoList);
        }
    }


    /**
     * 对文章进行排序，截取前30条文章，存入Redis数据库
     * @param key
     * @param curChannelHotArticle
     */
    private void sortedAndCacheHotArticle(String key, List<HotArticleVo> curChannelHotArticle) {
        //对文章按分值排序（倒序）
        curChannelHotArticle.sort(new Comparator<HotArticleVo>() {
            /**
             * 升序：o1 -> o2
             * 降序：o2 -> o1
             * @param o1
             * @param o2
             * @return
             */
            @Override
            public int compare(HotArticleVo o1, HotArticleVo o2) {
                return o2.getScore().compareTo(o1.getScore());
            }
        });

        //如果超过30条，截取前30条
        if(curChannelHotArticle.size()>30){
            curChannelHotArticle = curChannelHotArticle.subList(0,30);
        }

        //存入redis缓存
        redisTemplate.opsForValue().set(key, JsonUtils.toString(curChannelHotArticle));
    }

    /**
     * 计算所有的文章的分值
     * @param apArticleList
     * @return
     */
    private List<HotArticleVo> computeScoreForArticles(List<ApArticle> apArticleList) {
        List<HotArticleVo> hotArticleVoList = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(apArticleList)){
            apArticleList.forEach(apArticle -> {
                HotArticleVo articleVo = BeanHelper.copyProperties(apArticle,HotArticleVo.class);
                //计算一篇文章分值
                int score = computeScore(apArticle);
                articleVo.setScore(score);
                hotArticleVoList.add(articleVo);
            });
        }
        return hotArticleVoList;
    }

    /**
     * 计算一篇文章分值
     *    阅读 1
     *    点赞 3
     *    评论 5
     *    收藏 8
     * @param apArticle
     * @return
     */
    private int computeScore(ApArticle apArticle) {
        int score = 0;
        if(apArticle.getLikes()!=null){
            score+=apArticle.getLikes()* ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        if(apArticle.getComment()!=null){
            score+=apArticle.getComment()* ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if(apArticle.getCollection()!=null){
            score+=apArticle.getCollection()* ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        if(apArticle.getViews()!=null){
            score+=apArticle.getViews();
        }
        return score;
    }

    @Override
    public void updateHotArticle(ArticleVisitStreamMsg streamMsg) {
        Long articleId = streamMsg.getArticleId();
        Long view = streamMsg.getView();
        Long like = streamMsg.getLike();
        Long collect = streamMsg.getCollect();
        Long comment = streamMsg.getComment();

        ApArticle apArticle = apArticleMapper.selectById(articleId);
        if(apArticle==null){
            return;
        }

        //一、更新MySQL数据
        if(view!=null){
            apArticle.setViews(apArticle.getViews()+view.intValue());
        }
        if(like!=null){
            apArticle.setLikes(apArticle.getLikes()+like.intValue());
        }
        if(collect!=null){
            apArticle.setCollection(apArticle.getCollection()+collect.intValue());
        }
        if(comment!=null){
            apArticle.setComment(apArticle.getComment()+comment.intValue());
        }
        apArticleMapper.updateById(apArticle);

        //二、更新redis缓存数据

        //更新指定频道的缓存
        String key = RedisConstants.HOT_ARTICLE_FIRST_PAGE+apArticle.getChannelId();
        updateCacheHotArticle(key,apArticle);

        //更新推荐频道的缓存
        key = RedisConstants.HOT_ARTICLE_FIRST_PAGE+RedisConstants.DEFAULT_TAG;
        updateCacheHotArticle(key,apArticle);
    }

    /**
     * 更新redis缓存数据
     * @param key
     * @param apArticle
     */
    private void updateCacheHotArticle(String key, ApArticle apArticle) {
        //1.从redis取出缓存数据
        String redisData = redisTemplate.opsForValue().get(key);
        if(StringUtils.isNotEmpty(redisData)){
            List<HotArticleVo> hotArticleVoList = JsonUtils.toList(redisData, HotArticleVo.class);

            //重新计算分值
            int socre = computeScore(apArticle);

            //判断当前需要更新的文章是否在缓存中

            //存在于缓存的情况
            boolean flag = false;
            for(HotArticleVo hotArticleVo:hotArticleVoList){
                if(hotArticleVo.getId().equals(apArticle.getId())){
                    hotArticleVo.setScore(socre);
                    flag = true;
                }
            }

            //不存在于缓存的情况
            if(!flag){
                //把当前文章存入缓存列表
                HotArticleVo hotArticleVo = BeanHelper.copyProperties(apArticle, HotArticleVo.class);
                hotArticleVo.setScore(socre);
                hotArticleVoList.add(hotArticleVo);
            }

            //重新排序，多余数据截取，缓存redis
            sortedAndCacheHotArticle(key,hotArticleVoList);
        }

    }
}
